<template>
    <h1>Earth</h1>
    <div class="container" ref="ContainerRef" :style="{ width: size.width + 'px', height: size.height + 'px' }"></div>
</template>

<style scoped>
.container {
    background-color: aquamarine;
}
</style>

<script setup lang="ts" name="earth">
import { onUnmounted, ref } from 'vue';
import DefaultScene from '../libs/scene2'
import * as THREE from 'three';
import TWEEN from 'tween.ts';
import EarthImage from '../images/earth/earth.png'
import LightImage from '../images/earth/light_column.png'
import WaveImage from '../images/earth/label.png'
const defaultScene = new DefaultScene();
const {scene, size} = defaultScene;
/**
 * 初始化
 */
const ContainerRef = ref();
defaultScene.init(ContainerRef);

/**
 * 辅助线
 */
// AxesHelper：辅助观察的坐标系
const axesHelper = new THREE.AxesHelper(350);
scene.add(axesHelper);


/**
 * 业务相关
 */
defaultScene.useOrthCamera();
const Radius = 250;
const GlobalGroup = new THREE.Group();
scene.add(GlobalGroup);
/**
 * 经纬度转世界坐标
 * @param lng 
 * @param lat 
 */
function wgs84ToWorldPosition(lng: number, lat: number) {
    // lng += 90;
    let y = Radius * Math.sin(lat / 180 * Math.PI);
    let x = Radius * Math.cos(lat / 180 * Math.PI) * Math.sin(lng / 180 * Math.PI);
    let z = Radius * Math.cos(lat / 180 * Math.PI) * Math.cos(lng / 180 * Math.PI);
    return new THREE.Vector3(x, y, z);
}

const loader = new THREE.TextureLoader(); // 纹理加载器
const mkWorld = () => {
    // 地图贴图
    const geometry = new THREE.SphereGeometry(250, 64, 32);
    const texture = loader.load(EarthImage);
    texture.offset.x += 0.25;
    texture.wrapS = THREE.RepeatWrapping;
    const material = new THREE.MeshBasicMaterial({ map: texture, transparent: true });
    const mesh = new THREE.Mesh(geometry, material);
    GlobalGroup.add(mesh);
    // 更大的球形，绘制所有顶点
    const geometry2 = new THREE.SphereGeometry(300, 64, 32);
    const material2 = new THREE.PointsMaterial({ color: 0x00ccff, size: 1 })
    const point = new THREE.Points(geometry2, material2);
    GlobalGroup.add(point);
    const obj = { degree: 0 };
    // 全局加一个相机旋转动画
    const animateWorld = () => {
        GlobalGroup.rotation.y = obj.degree;
        new TWEEN.Tween(obj).to({ degree: Math.PI * 2 }, 40000).onUpdate(() => {
            GlobalGroup.rotation.y = obj.degree;
        }).onComplete(() => {
            obj.degree = 0;
            animateWorld();
        }).start();
    };
    animateWorld();
}
mkWorld();


// 创建机场
const mkAirport = (lat: number, lng: number) => {
    let pos = wgs84ToWorldPosition(lng, lat);
    // 生成光柱
    const lightHeight = 50;
    const geometry3 = new THREE.PlaneGeometry(6, 50);
    let texture3 = loader.load(LightImage);
    const material3 = new THREE.MeshBasicMaterial({
        //设置矩形网格模型的纹理贴图(光柱特效)
        map: texture3,
        // 双面显示
        side: THREE.DoubleSide,
        transparent: true
        // 开启透明效果，否则颜色贴图map的透明不起作用
    });
    const plane = new THREE.Mesh(geometry3, material3);
    plane.position.y = lightHeight / 2;
    const plane2 = plane.clone().rotateY(Math.PI / 2)
    const groupMesh = new THREE.Group()
    groupMesh.add(plane, plane2);
    groupMesh.position.copy(pos);
    const quaternion = new THREE.Quaternion();
    const vec1 = new THREE.Vector3(pos.z, 0, 0);
    const vec2 = new THREE.Vector3(0, 0, pos.x);
    const vec3 = new THREE.Vector3();
    vec3.subVectors(vec2, vec1);
    // 旋转光柱
    quaternion.setFromAxisAngle(vec3.normalize(), - 0.5 * Math.PI + lat * Math.PI / 180);
    groupMesh.applyQuaternion(quaternion)
    groupMesh.position.copy(pos);

    // 水波纹效果
    const geometry4 = new THREE.PlaneGeometry(12, 12);
    const texture4 = loader.load(WaveImage);
    const material4 = new THREE.MeshBasicMaterial({ transparent: true, side: THREE.DoubleSide, map: texture4, color: 0xff00ff });
    const plane4 = new THREE.Mesh(geometry4, material4);
    plane4.rotateX(Math.PI / 2)
    groupMesh.add(plane4);
    GlobalGroup.add(groupMesh);
    // 水波纹动画
    const animateWave = () => {
        const obj = { scale: 1, opacity: 1 };
        plane4.scale.set(obj.scale, obj.scale, obj.scale);
        new TWEEN.Tween(obj).to({ scale: 2, opacity: 0.5 }, 2000).onUpdate(() => {
            plane4.scale.set(obj.scale, obj.scale, obj.scale);
            material4.opacity = obj.opacity;
        }).onComplete(() => {
            obj.scale = 1;
            obj.opacity = 1;
            animateWave();
        }).start();
    }
    animateWave();
}

const citys: any = {
    hz: { lat: 30, lng: 120 },
    bj: { lat: 39.87, lng: 116.38 }
}

mkAirport(citys.hz.lat, citys.hz.lng);
mkAirport(citys.bj.lat, citys.bj.lng);

/**
 * 创建轨道
 */
const mkOrbits = () => {
    // 生成圆环
    const arc = new THREE.ArcCurve(0, 0, Radius * (1.1 + Math.random() * 0.4), 0, 2 * Math.PI);
    const points = arc.getPoints(100);

    // 创建一个旋转矩阵
    const mat4 = new THREE.Matrix4();
    const eular = new THREE.Euler((Math.random() - 1) * Math.PI, (Math.random() - 1) * Math.PI, (Math.random() - 1) * Math.PI);
    mat4.makeRotationFromEuler(eular);

    const geometry4 = new THREE.BufferGeometry();
    geometry4.setFromPoints(points);
    // 几何体旋转
    geometry4.applyMatrix4(mat4);
    const material4 = new THREE.LineBasicMaterial({
        color: 0x00fffff
    });
    const line4 = new THREE.Line(geometry4, material4);
    const groupMesh2 = new THREE.Group();
    groupMesh2.add(line4);
    // 轨道上创建一个卫星
    const geometry5 = new THREE.SphereGeometry(4);
    const material5 = new THREE.MeshBasicMaterial({ color: 0xff0000 });
    const mesh5 = new THREE.Mesh(geometry5, material5);
    const pointArr = geometry4.attributes.position.array;
    mesh5.position.set(pointArr[0], pointArr[1], pointArr[2]); // 初始化卫星的位置
    groupMesh2.add(mesh5);

    let times = 0;
    // 卫星动画
    const animateSatellite = () => {
        let point = { x: pointArr[times * 3], y: pointArr[times * 3 + 1], z: pointArr[times * 3 + 2] };
        new TWEEN.Tween(mesh5.position).to(point, 200).onComplete(() => {
            mesh5.position.set(point.x, point.y, point.z);
            animateSatellite();
        }).start();
        times++;
        if (times >= pointArr.length / 3 - 1) {
            times = 0;
        }
    }
    GlobalGroup.add(groupMesh2);
    animateSatellite();
}

mkOrbits();
mkOrbits();


// 航线

const mkAirLine = (city1: any, city2: any) => {
    let pos1 = wgs84ToWorldPosition(city1.lng, city1.lat);
    let pos2 = wgs84ToWorldPosition(city2.lng, city2.lat);
    let centerVec = new THREE.Vector3(pos1.x / 2 + pos2.x / 2, pos1.y / 2 + pos2.y / 2, pos1.z / 2 + pos2.z / 2); // 航线圆心方向
    let centerPos = centerVec.clone().normalize().multiplyScalar((Math.random() * 0.3 + 0.7) * Radius);
    let lineRadius = centerPos.clone().sub(pos1).length();
    let vec1 = pos1.clone().sub(centerPos).normalize();
    let vec2 = pos2.clone().sub(centerPos).normalize();
    let posVec = pos1.clone().sub(pos2);
    let degree = Math.acos(vec1.dot(vec2));
    console.log('lineRadius', lineRadius, 'centerPos', centerPos.length());

    // 画出圆弧
    const arc6 = new THREE.ArcCurve(0, 0, lineRadius, 0, degree);
    const points6 = arc6.getPoints(100);
    const geometry6 = new THREE.BufferGeometry();
    geometry6.setFromPoints(points6);
    const material6 = new THREE.LineBasicMaterial({
        color: 0xFFDEAD,
        linewidth: 2
    });
    let attr = geometry6.attributes.position;
    let count = attr.count - 1;
    let items = attr.array;
    let lineStartPoint = new THREE.Vector3(items[0], items[1], items[2]);
    let lineEndPoint = new THREE.Vector3(items[count * 3], items[count * 3 + 1], items[count * 3 + 2]);
    let lineCenterPoint = new THREE.Vector3(lineStartPoint.x / 2 + lineEndPoint.x / 2, lineStartPoint.y / 2 + lineEndPoint.y / 2, lineStartPoint.z / 2 + lineEndPoint.z / 2);
    let lineVec = lineEndPoint.clone().sub(lineStartPoint);
    let rotateDegree = Math.acos(lineVec.normalize().dot(posVec.normalize()));
    const groupMesh6 = new THREE.Group();
    const line6 = new THREE.Line(geometry6, material6);
    line6.position.sub(lineCenterPoint);
    groupMesh6.position.copy(centerVec);
    const vec3 = new THREE.Vector3();
    vec3.crossVectors(lineVec, posVec).normalize(); // 沿着两个向量的叉积方向旋转
    let quaternion = new THREE.Quaternion();
    quaternion.setFromAxisAngle(vec3, rotateDegree);
    groupMesh6.applyQuaternion(quaternion);
    groupMesh6.add(line6);

    const geometry7 = new THREE.TorusGeometry(lineRadius, 1, 16, 100, Math.PI / 25);
    const material7 = new THREE.MeshBasicMaterial({ color: 0xffff00 });
    const torus = new THREE.Mesh(geometry7, material7);
    torus.position.sub(lineCenterPoint);

    groupMesh6.add(torus);
    GlobalGroup.add(groupMesh6);

    const airDegree = { degree: degree };

    const animateAirplane = () => {
        let quaternion2 = new THREE.Quaternion();
        quaternion2.setFromAxisAngle(new THREE.Vector3(0, 0, 1), airDegree.degree);
        torus.setRotationFromQuaternion(quaternion2);
        new TWEEN.Tween(airDegree).to({ degree: 0 }, lineRadius * degree * 100).onUpdate(() => {
            let quaternion2 = new THREE.Quaternion();
            quaternion2.setFromAxisAngle(new THREE.Vector3(0, 0, 1), airDegree.degree);
            torus.setRotationFromQuaternion(quaternion2);
        }).onComplete(() => {
            airDegree.degree = degree;
            animateAirplane();
        }).start();
    }
    animateAirplane();
}
mkAirLine(citys.bj, citys.hz)

onUnmounted(() => {
    defaultScene.stopLoop();
})


</script>